#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "header.h"



int appartient_permutation(int c,int** tabl,int nb_permutations)
{
  
  int bool=0;
  int i=0;
  int res=-1;

 
  while ((bool==0) && (i<nb_permutations*2))
    {
      
      if (tabl[i][0]==c)
	{
	  bool=1;
	  res=tabl[i][1];
	}
      i++;
    }
    
  return res;
}



void decaler_rotor(Rotor* r)
{
  int i=0;
  int tmp = r->sorties[0];
  int temp;


  for (i=0;i<25;i++)
    {
      temp = (r->sorties[i+1]-1);
      if (temp<0)
	temp=25;
      r->sorties[i]=temp;
    }
  if (tmp==0)
    tmp=26;
  r->sorties[25]=(tmp-1);
}



void mouvement_rotors(Rotor* r1, Rotor* r2, Rotor* r3, int* pos_r1, int* pos_r2, int* pos_r3)
{
  *(pos_r1)=(*(pos_r1)+1)%26;
  decaler_rotor(r1);  

   if (*(pos_r1)==r1->encoche)
    {
      *(pos_r2)=(*(pos_r2)+1)%26;
      decaler_rotor(r2);
    }
  
  if (*(pos_r2)==r2->encoche)
    {
      *(pos_r3)=(*(pos_r3)+1)%26;
      decaler_rotor(r3);
      *(pos_r2)=(*(pos_r2)+1)%26;
      decaler_rotor(r2);
    }
} 







int traitement(Rotor* r1, Rotor* r2, Rotor* r3, Reflecteur* refl, Plugboard* plugb, int* pos_r1, int* pos_r2, int* pos_r3, int c, int nb_permutations)
{

  int temp;
  int temp2;
  int i=0,bool=0;
  
  
  mouvement_rotors(r1,r2,r3,pos_r1,pos_r2,pos_r3);
  
  temp=appartient_permutation(c,plugb->connexions,nb_permutations);
  
  if (temp<0)
    temp=c;
  
  temp2 = r1->sorties[temp]; /* passage au rotor 1 */
 
  temp = r2->sorties[temp2];  /* passage au rotor 2 */

  temp2 = r3->sorties[temp];  /* passage au rotor 3 */


  temp = refl->sorties[temp2];


  i=0;
  bool=0;


  while ((i<26) && (bool!=-1))
    {
      if (r3->sorties[i]==temp)
	{
	  bool=-1;
	  temp2 = i;
	}

      else
	i++;
    }

  i=0;
  bool=0;


  while ((i<26) && (bool!=-1))
    {
      if (r2->sorties[i]==temp2)
	{
	  bool=-1;
	  temp = i;
	}

      else
	i++;
    }


  i=0;
  bool=0;

  while ((i<26) && (bool!=-1))
    {
      if (r1->sorties[i]==temp)
	{
	  bool=-1;
	  temp2 = i;
	}

      else
	i++;
    }

 
  temp = appartient_permutation(temp2,plugb->connexions,nb_permutations);
 
  if (temp!=-1)
    return temp;
    else
  return temp2;
}







void affichage_machine(int pos_r1, int pos_r2, int pos_r3, int c, int flag) /* si c<0 juste affichage position des rotors, flag == -1 : afficher d'abord c */
{
  if (flag!=-1)
    {
      printf("%c\t%c\t%c\n",int_to_char(pos_r1,0),int_to_char(pos_r2,0),int_to_char(pos_r3,0));
      
      if (c>=0)
	{
	  printf("  %c\n",int_to_char(c,0));
	}
    }

  else 
    {
      if (c>=0)
	{
	  printf("  %c\n",int_to_char(c,0));
	}
      printf("%c\t%c\t%c\n",int_to_char(pos_r1,0),int_to_char(pos_r2,0),int_to_char(pos_r3,0));
      
    }


}












int main(int argc, char** argv, char** argenv) {






  char c; /* caractère de saisie de l'utilisateur */
  int res; /* le résultat du codage de c par la machine */
  int pos_r1;
  int pos_r2;
  int pos_r3;
  int d;
  char* tmp;
  char* texte;
  int choix; /* ==0 : -trace activée on affiche lettre par lettre avec wait? ; sinon ==1 : -saisie ; sinonc -print ==2 on affiche direct le résultat */
  int i;
  int nb_permutations; /* le nombre de permutations du plugboard */
  

  /* déclaration des rotors, du réflecteur et du plugboard */
  Rotor* rotor1;
  Rotor* rotor2;
  Rotor* rotor3;
  Reflecteur* refl;
  Plugboard* plugb;
  



 

  
 
  plugb = (Plugboard*) malloc(sizeof(Plugboard));
  plugb->connexions = (int**) malloc(sizeof(int*)*20);
  for (i=0; i<20; i++)
    plugb->connexions[i]=(int*) malloc (sizeof(int)*2); 
  nb_permutations = traitement_machine(argc, argv, &choix, &texte,plugb);



 /* déclaration des rotors, du réflecteur et du plugboard */
  rotor1 = (Rotor*) malloc(sizeof(Rotor));
  rotor1->encoche=12;
  
  rotor2 = (Rotor*) malloc(sizeof(Rotor));
  rotor2->encoche=16;

  rotor3 = (Rotor*) malloc(sizeof(Rotor));
  rotor3->encoche=8;

  refl = (Reflecteur*) malloc(sizeof(Reflecteur));
  

  /* emplacements pour les permutations */
  rotor1->sorties = (int*) malloc(sizeof(int)*26);
  rotor2->sorties = (int*) malloc(sizeof(int)*26);
  rotor3->sorties = (int*) malloc(sizeof(int)*26);
  refl->sorties = (int*) malloc(sizeof(int)*26);
  



  /* permutations du rotor1 */
  /* rotor1->sorties[0]=1;
  rotor1->sorties[1]=3;
  rotor1->sorties[2]=0;
  rotor1->sorties[3]=2;
  rotor1->sorties[4]=8;
  rotor1->sorties[5]=7;
  rotor1->sorties[6]=4;
  rotor1->sorties[7]=10;
  rotor1->sorties[8]=9;
  rotor1->sorties[9]=12;
  rotor1->sorties[10]=5;
  rotor1->sorties[11]=13;
  rotor1->sorties[12]=6;
  rotor1->sorties[13]=14;
  rotor1->sorties[14]=11;
  rotor1->sorties[15]=16;
  rotor1->sorties[16]=17;
  rotor1->sorties[17]=19;
  rotor1->sorties[18]=21;
  rotor1->sorties[19]=15;
  rotor1->sorties[20]=18;
  rotor1->sorties[21]=20;
  rotor1->sorties[22]=25;
  rotor1->sorties[23]=24;
  rotor1->sorties[24]=23;
  rotor1->sorties[25]=22;*/




  /* permutations du rotor1 */
  rotor1->sorties[0]=4;
  rotor1->sorties[1]=10;
  rotor1->sorties[2]=12;
  rotor1->sorties[3]=5;
  rotor1->sorties[4]=11;
  rotor1->sorties[5]=6;
  rotor1->sorties[6]=3;
  rotor1->sorties[7]=16;
  rotor1->sorties[8]=21;
  rotor1->sorties[9]=25;
  rotor1->sorties[10]=13;
  rotor1->sorties[11]=19;
  rotor1->sorties[12]=14;
  rotor1->sorties[13]=22;
  rotor1->sorties[14]=24;
  rotor1->sorties[15]=7;
  rotor1->sorties[16]=23;
  rotor1->sorties[17]=20;
  rotor1->sorties[18]=18;
  rotor1->sorties[19]=15;
  rotor1->sorties[20]=0;
  rotor1->sorties[21]=8;
  rotor1->sorties[22]=1;
  rotor1->sorties[23]=17;
  rotor1->sorties[24]=2;
  rotor1->sorties[25]=9;


  /* permutations du rotor2 */
  /* rotor2->sorties[0]=14;
  rotor2->sorties[1]=9;
  rotor2->sorties[2]=0;
  rotor2->sorties[3]=12;
  rotor2->sorties[4]=20;
  rotor2->sorties[5]=3;
  rotor2->sorties[6]=5;
  rotor2->sorties[7]=2;
  rotor2->sorties[8]=10;
  rotor2->sorties[9]=4;
  rotor2->sorties[10]=1;
  rotor2->sorties[11]=8;
  rotor2->sorties[12]=16;
  rotor2->sorties[13]=7;
  rotor2->sorties[14]=11;
  rotor2->sorties[15]=18;
  rotor2->sorties[16]=23;
  rotor2->sorties[17]=19;
  rotor2->sorties[18]=17;
  rotor2->sorties[19]=21;
  rotor2->sorties[20]=22;
  rotor2->sorties[21]=6;
  rotor2->sorties[22]=13;
  rotor2->sorties[23]=25;
  rotor2->sorties[24]=15;
  rotor2->sorties[25]=24;*/


 /* permutations du rotor 2 */
  rotor2->sorties[0]=0;
  rotor2->sorties[1]=9;
  rotor2->sorties[2]=3;
  rotor2->sorties[3]=10;
  rotor2->sorties[4]=18;
  rotor2->sorties[5]=8;
  rotor2->sorties[6]=17;
  rotor2->sorties[7]=20;
  rotor2->sorties[8]=23;
  rotor2->sorties[9]=1;
  rotor2->sorties[10]=11;
  rotor2->sorties[11]=7;
  rotor2->sorties[12]=22;
  rotor2->sorties[13]=19;
  rotor2->sorties[14]=12;
  rotor2->sorties[15]=2;
  rotor2->sorties[16]=16;
  rotor2->sorties[17]=6;
  rotor2->sorties[18]=25;
  rotor2->sorties[19]=13;
  rotor2->sorties[20]=15;
  rotor2->sorties[21]=24;
  rotor2->sorties[22]=5;
  rotor2->sorties[23]=21;
  rotor2->sorties[24]=14;
  rotor2->sorties[25]=4;

  /* permutations du rotor3 */
  /*rotor3->sorties[0]=6;
  rotor3->sorties[1]=4;
  rotor3->sorties[2]=9;
  rotor3->sorties[3]=20;
  rotor3->sorties[4]=18;
  rotor3->sorties[5]=0;
  rotor3->sorties[6]=2;
  rotor3->sorties[7]=8;
  rotor3->sorties[8]=5;
  rotor3->sorties[9]=7;
  rotor3->sorties[10]=12;
  rotor3->sorties[11]=3;
  rotor3->sorties[12]=11;
  rotor3->sorties[13]=1;
  rotor3->sorties[14]=10;
  rotor3->sorties[15]=13;
  rotor3->sorties[16]=15;
  rotor3->sorties[17]=25;
  rotor3->sorties[18]=14;
  rotor3->sorties[19]=21;
  rotor3->sorties[20]=24;
  rotor3->sorties[21]=23;
  rotor3->sorties[22]=17;
  rotor3->sorties[23]=22;
  rotor3->sorties[24]=16;
  rotor3->sorties[25]=19;*/




 /* permutations du rotor 3 */
  rotor3->sorties[0]=1;
  rotor3->sorties[1]=3;
  rotor3->sorties[2]=5;
  rotor3->sorties[3]=7;
  rotor3->sorties[4]=9;
  rotor3->sorties[5]=11;
  rotor3->sorties[6]=2;
  rotor3->sorties[7]=15;
  rotor3->sorties[8]=17;
  rotor3->sorties[9]=19;
  rotor3->sorties[10]=23;
  rotor3->sorties[11]=21;
  rotor3->sorties[12]=25;
  rotor3->sorties[13]=13;
  rotor3->sorties[14]=24;
  rotor3->sorties[15]=4;
  rotor3->sorties[16]=8;
  rotor3->sorties[17]=22;
  rotor3->sorties[18]=6;
  rotor3->sorties[19]=0;
  rotor3->sorties[20]=10;
  rotor3->sorties[21]=12;
  rotor3->sorties[22]=20;
  rotor3->sorties[23]=18;
  rotor3->sorties[24]=16;
  rotor3->sorties[25]=14;


  /* permutations du réflecteur */
  refl->sorties[0]=24;
  refl->sorties[1]=17;
  refl->sorties[2]=20;
  refl->sorties[3]=7;
  refl->sorties[4]=16;
  refl->sorties[5]=18;
  refl->sorties[6]=11;
  refl->sorties[7]=3;
  refl->sorties[8]=15;
  refl->sorties[9]=23;
  refl->sorties[10]=13;
  refl->sorties[11]=6;
  refl->sorties[12]=14;
  refl->sorties[13]=10;
  refl->sorties[14]=12;
  refl->sorties[15]=8;
  refl->sorties[16]=4;
  refl->sorties[17]=1;
  refl->sorties[18]=5;
  refl->sorties[19]=25;
  refl->sorties[20]=2;
  refl->sorties[21]=22;
  refl->sorties[22]=21;
  refl->sorties[23]=9;
  refl->sorties[24]=0;
  refl->sorties[25]=19;


  /* permutations du réflecteur 
  refl->sorties[0]=5;
  refl->sorties[1]=21;
  refl->sorties[2]=15;
  refl->sorties[3]=9;
  refl->sorties[4]=8;
  refl->sorties[5]=0;
  refl->sorties[6]=14;
  refl->sorties[7]=24;
  refl->sorties[8]=4;
  refl->sorties[9]=3;
  refl->sorties[10]=17;
  refl->sorties[11]=25;
  refl->sorties[12]=23;
  refl->sorties[13]=22;
  refl->sorties[14]=6;
  refl->sorties[15]=2;
  refl->sorties[16]=19;
  refl->sorties[17]=10;
  refl->sorties[18]=20;
  refl->sorties[19]=16;
  refl->sorties[20]=18;
  refl->sorties[21]=1;
  refl->sorties[22]=13;
  refl->sorties[23]=12;
  refl->sorties[24]=7;
  refl->sorties[25]=11;

  */
  

  
  c='a'; /* caractère de saisie de l'utilisateur */
  
  pos_r1=char_to_int(argv[1][0]);
  pos_r2=char_to_int(argv[2][0]);
  pos_r3=char_to_int(argv[3][0]);


  /*  if(system("clear")<0)
    {
      fprintf(stderr,"Erreur system(\"clear\")\n");
      }*/

  if (choix==1)
    {

      affichage_machine(pos_r1,pos_r2,pos_r3,-1,0); /* on affiche les rotors au commencement*/
      while (1)
	{
	  if (scanf("%c",&c)<0)
	    {
	      fprintf(stderr,"Erreur scanf Machine\n");
	    }
	  
	  if (c != '\n') /* vidage du buffer stdin pour enchainer correctement les scanf; */
	    { 
	      while ((d = getchar ()) != '\n' && d != EOF) 
		{ 
		  
		} 
	    }
	  
	  if (c!='$')
	    {
	      
	      res = traitement(rotor1,rotor2,rotor3,refl,plugb,&pos_r1,&pos_r2,&pos_r3,char_to_int(c),nb_permutations);
	      affichage_machine(pos_r1,pos_r2,pos_r3,res,0);
	      
	    }
	  
	  else 
	    {
	      break;
	    }
	}
      
    }
  

  else 
    {
      tmp = (char*) malloc((int)strlen(texte));
      if (choix==2)
	{
	  for (d=0;d<strlen(texte);d++)
	    {
	      res = traitement(rotor1,rotor2,rotor3,refl,plugb,&pos_r1,&pos_r2,&pos_r3,char_to_int(texte[d]),nb_permutations);
	      tmp[d]=int_to_char(res,0);
	    }
	  
	  affichage_machine(pos_r1,pos_r2,pos_r3,-1,0); /* -1 dans le cas où on veut juste afficher la position des rotors. */
	  affichage(tmp);
	}

      else /* choix==0 */
	{
	  affichage_machine(pos_r1,pos_r2,pos_r3,-1,0);
	  for (d=0;d<strlen(texte);d++)
	    {
	      res = traitement(rotor1,rotor2,rotor3,refl,plugb,&pos_r1,&pos_r2,&pos_r3,char_to_int(texte[d]),nb_permutations);
	      tmp[d]=int_to_char(res,0);
	      affichage_machine(pos_r1,pos_r2,pos_r3,res,-1);
	      sleep(1);
	    }
	  
	  
	  affichage(tmp);

	  
	}
      free(tmp);
      free(texte);
    }

  
  



  free(rotor1->sorties);
  free(rotor2->sorties);
  free(rotor3->sorties);
  free(refl->sorties);
  for (i=0;i<20;i++)
    free(plugb->connexions[i]);
  free(plugb->connexions);

  free(rotor1);
  free(rotor2);
  free(rotor3);
  free(refl);
  free(plugb);
  return (EXIT_SUCCESS); 
}

